package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDto;
import com.tianji.api.cache.CategoryCache;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.client.search.SearchClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.ObjectUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.common.utils.*;
import com.tianji.learning.domain.dto.QuestionFormDTO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.QuestionAdminPageQuery;
import com.tianji.learning.domain.query.QuestionPageQuery;
import com.tianji.learning.domain.vo.QuestionAdminVO;
import com.tianji.learning.domain.vo.QuestionVO;
import com.tianji.learning.enums.TextModerationServiceType;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.mapper.InteractionReplyMapper;
import com.tianji.learning.service.IInteractionQuestionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.utils.AliyunTextModerationHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 互动提问的问题表 服务实现类
 * </p>
 *
 * @author LYQ
 * @since 2024-06-25
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class InteractionQuestionServiceImpl extends ServiceImpl<InteractionQuestionMapper, InteractionQuestion> implements IInteractionQuestionService {
    private final InteractionReplyMapper replyMapper;
    private final UserClient userClient;
    private final SearchClient searchClient;
    private final CourseClient courseClient;
    private final CatalogueClient catalogueClient;
    private final CategoryCache categoryCache;
    private final AliyunTextModerationHandler aliyunTextModerationHandler;

    /**
     * 客户端 - 分页查询提问数据
     *
     * @param pageQuery
     * @return
     */
    @Override
    public PageDTO<QuestionVO> queryPage(QuestionPageQuery pageQuery) {
        //1、数据健壮性校验
        if (pageQuery.getCourseId() == null && pageQuery.getSectionId() == null) {
            throw new BadRequestException("课程id和章节id不能同时为空");
        }

        //2、分页查询问题主体
        Page<InteractionQuestion> questionPage = lambdaQuery()
                .select(InteractionQuestion.class, column -> !column.equals("description"))
                .eq(ObjectUtils.isNotEmpty(pageQuery.getCourseId()), InteractionQuestion::getCourseId, pageQuery.getCourseId())
                .eq(ObjectUtils.isNotEmpty(pageQuery.getSectionId()), InteractionQuestion::getSectionId, pageQuery.getSectionId())
                .eq(pageQuery.getOnlyMine(), InteractionQuestion::getUserId, UserContext.getUser())
                .eq(InteractionQuestion::getHidden, false)
                .page(pageQuery.toMpPageDefaultSortByCreateTimeDesc());
        List<InteractionQuestion> questionPageRecords = questionPage.getRecords();
        if (ObjectUtils.isEmpty(questionPageRecords)) {
            return PageDTO.empty(questionPage);
        }

        //3、查询缺失数属性数据：提问者昵称、头像；最近一次体提问的内容、最近一次回答的用户昵称
        Set<Long> latestAnswerIds = new HashSet<>(questionPageRecords.size());
        Set<Long> UserIds = new HashSet<>(questionPageRecords.size());
        for (InteractionQuestion questionPageRecord : questionPageRecords) {
            if (!questionPageRecord.getAnonymity()) {
                UserIds.add(questionPageRecord.getUserId());
            }
            latestAnswerIds.add(questionPageRecord.getLatestAnswerId());
        }


        //3.1 查询最新回答的内容
        Map<Long, InteractionReply> latestReplayMap = new HashMap<>(latestAnswerIds.size());
        if (ObjectUtils.isNotEmpty(latestAnswerIds)) {
            List<InteractionReply> latestReplayList = replyMapper.selectBatchIds(latestAnswerIds);
            if (ObjectUtils.isNotEmpty(latestReplayList)) {
                for (InteractionReply interactionReply : latestReplayList) {
                    latestReplayMap.put(interactionReply.getId(), interactionReply);
                    if (!interactionReply.getAnonymity()) {
                        UserIds.add(interactionReply.getUserId());
                    }
                }
            }
        }
        //3.2远程调用查询用户信息
        Map<Long, UserDTO> userDTOMap = new HashMap<>();
        if (!UserIds.isEmpty()) {
            List<UserDTO> userDTOS = userClient.queryUserByIds(UserIds);
            if (ObjectUtils.isNotEmpty(userDTOS)) {
                userDTOMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, userDTO -> userDTO));
            }
        }

        //4、遍历转换为Vo并填充属性
        List<QuestionVO> questionVOS = new ArrayList<>(questionPageRecords.size());
        for (InteractionQuestion questionPageRecord : questionPageRecords) {
            QuestionVO questionVO = BeanUtils.toBean(questionPageRecord, QuestionVO.class);
            //填充属性
            //填充最后一次回答的内容
            //填充最后一次回答问题的用户昵称
            InteractionReply latestReply = latestReplayMap.get(questionPageRecord.getLatestAnswerId());
            if (ObjectUtils.isNotEmpty(latestReply)) {
                questionVO.setLatestReplyContent(latestReply.getContent());
                UserDTO userInfo = userDTOMap.get(latestReply.getUserId());
                if (ObjectUtils.isNotEmpty(userInfo)) {
                    questionVO.setLatestReplyUser(userInfo.getName());
                }
            }
            //填充提问者昵称和提问者头像
            if (!questionPageRecord.getAnonymity()) {
                UserDTO userInfo = userDTOMap.get(questionPageRecord.getUserId());
                if (ObjectUtils.isNotEmpty(userInfo)) {
                    questionVO.setUserName(userInfo.getName());
                    questionVO.setUserIcon(userInfo.getIcon());
                }
            }
            questionVOS.add(questionVO);
        }
        //5、组装PageDto返回

        return PageDTO.of(questionPage, questionVOS);
    }

    /**
     * 新增提问
     *
     * @param questionDTO
     * @return
     */


    @Override
    public void insertQuestion(QuestionFormDTO questionDTO) {
        String label = aliyunTextModerationHandler.textModeration(questionDTO.getDescription(), TextModerationServiceType.LLM_QUERY_MODERATION);
        if (ObjectUtils.isNotEmpty(label) && !label.equals("nonLabel")) {
            throw new BadRequestException("提问内容包含违规内容:"+label);
        }
        // 1.获取登录用户
        Long userId = UserContext.getUser();
        // 2.数据转换
        InteractionQuestion question = BeanUtils.toBean(questionDTO, InteractionQuestion.class);
        // 3.补充数据
        question.setUserId(userId);
        // 4.保存问题
        save(question);
    }

    /**
     * 用户端 - 根据id查询问题详情
     *
     * @param id
     * @return
     */
    @Override
    public QuestionVO queryQuestionById(Long id) {
        //1、从数据库中查询对应问题数据
        InteractionQuestion question = getById(id);
        if (question == null || question.getHidden()) {
            // 没有数据或者是被隐藏了
            return null;
        }
        //2 查询提问者昵称和提问者头像
        UserDTO userInfo = null;
        if (!question.getAnonymity()) {
            userInfo = userClient.queryUserById(question.getUserId());
        }
        //3、转为Vo,填充属性
        QuestionVO questionVO = BeanUtils.copyBean(question, QuestionVO.class);
        if (ObjectUtils.isNotEmpty(userInfo)) {
            questionVO.setUserName(userInfo.getName());
            questionVO.setUserIcon(userInfo.getIcon());
        }

        //4、返回数据
        return questionVO;
    }

    /**
     * 管理端 - 分页查询提问数据
     *
     * @param pageQuery
     * @return
     */
    @Override
    public PageDTO<QuestionAdminVO> adminQueryPage(QuestionAdminPageQuery pageQuery) {
        //1、接用es分词查询匹配获取对应课程数据ids
        List<Long> courseIds = null;
        if (ObjectUtils.isNotEmpty(pageQuery.getCourseName())) {
            courseIds = searchClient.queryCoursesIdByName(pageQuery.getCourseName());
            if (ObjectUtils.isEmpty(courseIds)) {
                return PageDTO.empty(0L, 0L);
            }
        }
        //2、分页查询
        Page<InteractionQuestion> pageResult = this.lambdaQuery()
                .in(ObjectUtils.isNotEmpty(courseIds), InteractionQuestion::getCourseId, courseIds)
                .eq(ObjectUtils.isNotEmpty(pageQuery.getStatus()), InteractionQuestion::getStatus, pageQuery.getStatus())
                .ge(ObjectUtils.isNotEmpty(pageQuery.getBeginTime()), InteractionQuestion::getCreateTime, pageQuery.getBeginTime())
                .le(ObjectUtils.isNotEmpty(pageQuery.getEndTime()), InteractionQuestion::getCreateTime, pageQuery.getEndTime())
                .page(pageQuery.toMpPageDefaultSortByCreateTimeDesc());
        List<InteractionQuestion> records = pageResult.getRecords();
        if (ObjectUtils.isEmpty(records)) {
            return PageDTO.empty(pageResult);
        }
        //3、查询缺失数据（章节名称；课程名称、三级分类名称；提问者昵称；回答数量）
        //3.1收集userIds、courseIds、chapterIds
        Set<Long> UserIds = new HashSet<>(records.size());
        Set<Long> cIds = new HashSet<>(records.size());
        Set<Long> chapterIds = new HashSet<>(records.size());
        for (InteractionQuestion record : records) {
            UserIds.add(record.getUserId());
            cIds.add(record.getCourseId());
            chapterIds.add(record.getChapterId());
            chapterIds.add(record.getSectionId());
        }
        //3.2查询用户信息并转为map集合
        List<UserDTO> userInfoList = userClient.queryUserByIds(UserIds);
        Map<Long, String> userInfoMap = new HashMap<>(userInfoList.size());
        if (ObjectUtils.isNotEmpty(userInfoList)) {
            userInfoMap = userInfoList.stream().collect(Collectors.toMap(UserDTO::getId, UserDTO::getName));
        }
        //3.3查询课程信息并转为map集合
        List<CourseSimpleInfoDTO> courseInfoList = courseClient.getSimpleInfoList(cIds);
        Map<Long, CourseSimpleInfoDTO> courseInfoMap = new HashMap<>(courseInfoList.size());
        if (ObjectUtils.isNotEmpty(courseInfoList)) {
            courseInfoMap = courseInfoList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, Function.identity()));
        }
        //3.4查询小节信息并转为map集合
        List<CataSimpleInfoDTO> cateInfoList = catalogueClient.batchQueryCatalogue(chapterIds);
        Map<Long, String> cateInfoMap = new HashMap<>(cateInfoList.size());
        if (ObjectUtils.isNotEmpty(cateInfoList)) {
            cateInfoMap = cateInfoList.stream().collect(Collectors.toMap(CataSimpleInfoDTO::getId, CataSimpleInfoDTO::getName));
        }

        //4、循环遍历，补充缺失数据
        List<QuestionAdminVO> voList = new ArrayList<>(records.size());
        for (InteractionQuestion record : records) {
            //4.0拷贝属性
            QuestionAdminVO questionAdminVO = BeanUtils.toBean(record, QuestionAdminVO.class);
            //4.1填充UserName
            questionAdminVO.setUserName(userInfoMap.getOrDefault(record.getUserId(), ""));
            //4.2填充CourseName
            CourseSimpleInfoDTO courseInfo = courseInfoMap.get(record.getCourseId());
            if (ObjectUtils.isNotEmpty(courseInfo)) {
                questionAdminVO.setCourseName(courseInfo.getName());
            }
            //4.3填充章节名称
            questionAdminVO.setChapterName(cateInfoMap.getOrDefault(record.getChapterId(), ""));
            questionAdminVO.setChapterName(cateInfoMap.getOrDefault(record.getSectionId(), ""));
            //4.3填充三级分类名称
            String categoryName = "";
            if (ObjectUtils.isNotEmpty(courseInfo)) {
                categoryName = categoryCache.getCategoryNames(courseInfo.getCategoryIds());
            }
            questionAdminVO.setCategoryName(categoryName);
            //4.4填充回答数量
            questionAdminVO.setReplyTimes(record.getAnswerTimes());
            //4.5填充完成属性的Vo添加进集合中
            voList.add(questionAdminVO);
        }
        //5、组装数据，返回PageDTO
        return PageDTO.of(pageResult, voList);
    }

    /**
     * 用户端 - 根据id修改问题
     *
     * @param questionDTO@return
     */
    @Override
    public void updateQuestionById(Long id, QuestionFormDTO questionDTO) {
        if (id == null || ObjectUtils.isEmpty(questionDTO)) {
            return;
        }
        //1、根据Id查询问题信息
        InteractionQuestion question = this.getById(id);
        if (ObjectUtils.isEmpty(question)) {
            throw new BizIllegalException("对应问题不存在");
        }
        //2、拷贝属性
        question.setAnonymity(questionDTO.getAnonymity());
        question.setTitle(questionDTO.getTitle());
        question.setDescription(questionDTO.getDescription());
        question.setChapterId(questionDTO.getChapterId());
        question.setSectionId(questionDTO.getSectionId());
        //3、更新问题数据
        updateById(question);
    }

    /**
     * 用户端 - 根据id删除问题
     *
     * @param id
     * @return
     */
    @Override
    @Transactional
    public void deleteQuestionById(Long id) {
        //1、查询问题是否存在
        InteractionQuestion question = this.getById(id);
        if (ObjectUtils.isEmpty(question)) {
            throw new BizIllegalException("该问题不存在");
        }
        //2、校验问题是否为当前用户所提
        if (!question.getUserId().equals(UserContext.getUser())) {
            throw new BizIllegalException("不能删除其他用户的问题");
        }
        //3、删除问题下对应所有的回答、删除对应回答的所有评论
        this.removeById(id);
        //3.1、收集所有问答的id
        List<Long> answerIds = replyMapper.selectList(new LambdaQueryWrapper<InteractionReply>()
                        .select(InteractionReply::getId)
                        .eq(InteractionReply::getQuestionId, id))
                .stream().map(InteractionReply::getId).collect(Collectors.toList());
        //3.2、收集所有对应回答下的所有评论id
        List<Long> replayIds = replyMapper.selectList(new LambdaQueryWrapper<InteractionReply>()
                        .select(InteractionReply::getId)
                        .in(InteractionReply::getAnswerId, answerIds))
                .stream().map(InteractionReply::getId).collect(Collectors.toList());
        //3.3合并InteractionReply表的ids
        List<Long> interactionReplyIds = null;
        if (ObjectUtils.isNotEmpty(replayIds)) {
            interactionReplyIds = CollUtils.addAllIfNotContains(answerIds, replayIds);
        }
        //4、批量删除所有问题和评论
        if (ObjectUtils.isNotEmpty(interactionReplyIds)) {
            replyMapper.deleteBatchIds(interactionReplyIds);
        }
    }

    /**
     * 管理端 - 隐藏或显示问题
     *
     * @param id
     * @param hidden
     * @return
     */
    @Override
    public void hiddenChange(Long id, Boolean hidden) {
        if (ObjectUtils.isEmpty(id) || ObjectUtils.isEmpty(hidden)) {
            throw new BadRequestException("请求参数不能为空");
        }
        boolean updateResult = updateById(new InteractionQuestion().setId(id).setHidden(hidden));
        AssertUtils.isTrue(updateResult, "更新失败");
    }

    /**
     * 管理端 - 根据id查询问题详情
     *
     * @param id
     * @return
     */
    @Override
    public QuestionAdminVO adminQueryQuestionById(Long id) {
        //1、查询基本实体
        InteractionQuestion question = getById(id);
        //2、提问作者昵称、课程名称、教师名称、章、节名称、三级分类名称
        //2.1、查询用户信息(提问作者昵称、对应课程教师名称)
        UserDTO userInfo = userClient.queryUserById(question.getUserId());
        //2.2、查询课程信息(课程名称、教师Ids)
        CourseFullInfoDTO courseInfo = courseClient.getCourseInfoById(question.getCourseId(), false, true);
        List<Long> teacherIds = null;
        if (ObjectUtils.isNotEmpty(courseInfo)) {
            teacherIds = courseInfo.getTeacherIds();
        }
        //2.3、查询章节信息(章、节名称)
        List<CataSimpleInfoDTO> cateInfoList = catalogueClient.batchQueryCatalogue(CollUtils.newArrayList(question.getChapterId(), question.getSectionId()));
        Map<Long, String> cateInfoMap = new HashMap<>(cateInfoList.size());
        if (ObjectUtils.isNotEmpty(cateInfoList)) {
            cateInfoMap = cateInfoList.stream().collect(Collectors.toMap(CataSimpleInfoDTO::getId, CataSimpleInfoDTO::getName));
        }
        //2.4、查询三级分类名称
        String categoryName = "";
        if (ObjectUtils.isNotEmpty(courseInfo)) {
            categoryName = categoryCache.getCategoryNames(courseInfo.getCategoryIds());//三级分类名称
        }
        //3、转为Vo拷贝并填充属性
        //3.1转为Vo
        QuestionAdminVO questionAdminVO = BeanUtils.copyBean(question, QuestionAdminVO.class);
        //3.2填充UserName、UserIcon
        if (ObjectUtils.isNotEmpty(userInfo)) {
            questionAdminVO.setUserName(userInfo.getName());
            questionAdminVO.setUserIcon(userInfo.getIcon());
        }
        //3.3填充课程名称、教师名称
        if (ObjectUtils.isNotEmpty(courseInfo)) {
            questionAdminVO.setCourseName(courseInfo.getName());
            if (ObjectUtils.isNotEmpty(teacherIds)) {
                List<UserDTO> teacherInfoList = userClient.queryUserByIds(teacherIds);
                if (ObjectUtils.isNotEmpty(teacherInfoList)) {
                    questionAdminVO.setTeacherName(teacherInfoList.stream().map(UserDTO::getName).collect(Collectors.joining("、")));
                } else {
                    questionAdminVO.setTeacherName("");
                }
            }
        }
        //3.4填充章节名称
        if (ObjectUtils.isNotEmpty(cateInfoMap)) {
            questionAdminVO.setChapterName(cateInfoMap.getOrDefault(question.getChapterId(), ""));
            questionAdminVO.setSectionName(cateInfoMap.getOrDefault(question.getSectionId(), ""));
        }
        //3.5填充三级分类名称
        questionAdminVO.setCategoryName(categoryName);

        //3.6填充回复次数
        questionAdminVO.setReplyTimes(question.getAnswerTimes());

        //4、返回对应的VO
        return questionAdminVO;
    }
}
